class Billiard3 extends egret.DisplayObjectContainer {
    private ball0: Ball
    private ball1: Ball
    private bounce: number = -1.0
    public constructor() {
        super()
        this.once(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this)
    }

    private onAddToStage(evt: egret.Event): void {
        this.ball0 = new Ball(150)
        this.ball0.mass = 2
        this.ball0.x = this.stage.stageWidth - 200
        this.ball0.y = this.stage.stageHeight - 200
        this.ball0.vx = Math.random() * 10 - 5
        this.ball0.vy = Math.random() * 10 - 5
        this.addChild(this.ball0)

        this.ball1 = new Ball(90)
        this.ball1.mass = 1
        this.ball1.x = 100
        this.ball1.y = 100
        this.ball1.vx = Math.random() * 10 - 5
        this.ball1.vy = Math.random() * 10 - 5
        this.addChild(this.ball1)

        this.addEventListener(egret.Event.ENTER_FRAME, this.onEnterFrame, this)
    }

    private onEnterFrame(evt: egret.Event): void {
        this.ball0.x += this.ball0.vx
        this.ball0.y += this.ball0.vy
        this.ball1.x += this.ball1.vx
        this.ball1.y += this.ball1.vy
        this.checkCollection(this.ball0, this.ball1)
        this.checkWalls(this.ball0)
        this.checkWalls(this.ball1)
    }

    private checkCollection(ball0: Ball, ball1: Ball) {
        let dx = ball1.x - ball0.x
        let dy = ball1.y - ball0.y
        let dist = Math.sqrt(dx * dx + dy * dy)

        if (dist < ball0.radius + ball1.radius) {

            let angle = Math.atan2(dy, dx)
            let sin = Math.sin(angle)
            let cos = Math.cos(angle)

            // 旋转ball0的位置，是按照ball0进行旋转的，那么自己相对于自己的相对位置是0
            let x0 = 0
            let y0 = 0

            // 旋转ball1的位置，已知相对位置分别为dx, dy，那么直接进行旋转操作
            let x1 = dx * cos + dy * sin
            let y1 = dy * cos - dx * sin
            
            // 旋转ball0的速度
            let vx0 = ball0.vx * cos + ball0.vy * sin
            let vy0 = ball0.vy * cos - ball0.vx * sin

            // 旋转ball1的速度
            let vx1 = ball1.vx * cos + ball1.vy * sin
            let vy1 = ball1.vy * cos - ball1.vx * sin

            // 碰撞反应
            let vxTotal = vx0 - vx1
            vx0 = ((ball0.mass - ball1.mass) * vx0 + 2 * ball1.mass * vx1) / (ball0.mass + ball1.mass)
            vx1 = vxTotal + vx0

            // 把位置旋转回去
            let x0Final = x0 * cos - y0 * sin
            let y0Final = y0 * cos + x0 * sin
            let x1Final = x1 * cos - y1 * sin
            let y1Final = y1 * cos + x1 * sin

            // 将位置调整到实际的屏幕位置
            ball1.x = ball0.x + x1Final
            ball1.y = ball0.y + y1Final
            ball0.x = ball0.x + x0Final
            ball0.y = ball0.y + y0Final

            // 将速度旋转回去
            ball0.vx = vx0 * cos - vy0 * sin
            ball0.vy = vy0 * cos + vx0 * sin
            ball1.vx = vx1 * cos - vy1 * sin
            ball1.vy = vy1 * cos + vx1 * sin

            // 防止嵌入
            ball0.x += ball0.vx
            ball0.y += ball0.vy
            ball1.x += ball1.vx
            ball1.y += ball1.vy
        }
    }

    private checkWalls(ball: Ball) {
        if (ball.x + ball.radius > this.stage.stageWidth) {
            ball.x = this.stage.stageWidth - ball.radius
            ball.vx *= this.bounce
        }
        else if (ball.x - ball.radius < 0) {
            ball.x = ball.radius
            ball.vx *= this.bounce
        }
        if (ball.y + ball.radius > this.stage.stageHeight) {
            ball.y = this.stage.stageHeight - ball.radius
            ball.vy *= this.bounce
        }
        else if (ball.y - ball.radius < 0) {
            ball.y = ball.radius
            ball.vy *= this.bounce
        }
    }
}